package com.tianquan.Transactional;

import com.tianquan.Transactional.annotation.RedissonLock;
import org.aopalliance.intercept.MethodInvocation;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.redis.annotation
 * @Author: tianquan
 * @CreateTime: 2024-10-03  21:16
 * @Description: redisson锁管理器
 * @Version: 1.0
 */
@Component
public final class RedissonLockManager implements BeanPostProcessor {

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        /**
         * 如果是代理对象 获取真正的被代理的类的类对象
         * 必须要这样写 如果实现after方法来实现的话
         * 因为如果类中存在@Transaction 注解的话 这里传入的bean就是代理对象了
         */
        Class<?> targetClass = AopUtils.getTargetClass(bean);
        // 循环判断bean的每个方式是否标记了 @RedissonLock 注解 如果有标记 则为他生成代理
        Method[] methods = targetClass.getDeclaredMethods();
        Object proxy;
        for (Method method : methods) {
            proxy = interceptor(bean, method);
            if (null == proxy) continue;
            return proxy;
        }
        return bean;
    }

    // 这里也是保持和 spring 事务一致 只允许公共方法
    public boolean isPublic(int mod) {
        return Modifier.isPublic(mod);
    }

    // 判断是否存在 @RedissonLock 注解
    public RedissonLock hasRedissonLock(Method method) {
        return method.getAnnotation(RedissonLock.class);
    }

    /**
     * 如果条件都满足 那么我们对这个类进行代理
     */
    public Object interceptor(Object bean, Method method) {
        RedissonLock redissonLock;
        if (isPublic(method.getModifiers()) && (redissonLock = hasRedissonLock(method)) != null) {
            // 进入这里 我们就代理这个类 ProxyUtils 会在下面给出来
            return ProxyUtils.getProxy(bean, this::methodInterceptor);
        }
        return null;
    }

    // 这里是具体的代理逻辑
    public Object methodInterceptor(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        RedissonLock redissonLock = hasRedissonLock(method);
        // 如果调用的方法不存在 redissonLock 注解 直接返回
        if (redissonLock != null) {
            // 这里加锁
            RLock lock = redissonClient.getLock(redissonLock.lockName());
            lock.lock(redissonLock.timeOut(), redissonLock.unit());
            try {
                // 判断是否开启事务
                Transactional transactional = redissonLock.transactional();
                if (transactional != null) {
                    // 这里是我们手动对spring事务进行管理,这里就是开启事务
                    TransactionStatus status = TransactionalManager.begin(transactional);
                    // 用来存储返回
                    Object proceed = null;
                    try {
                        // 执行被代理的方法的逻辑
                        proceed = invocation.proceed();
                    } catch (Exception e) {
                        // 回滚
                        e.printStackTrace();
                        TransactionalManager.rollback(status);
                    }
                    // 提交事务
                    TransactionalManager.commit(status);
                    return proceed;
                }
                return invocation.proceed();
            } finally {
                lock.unlock();
            }
        }
        return invocation.proceed();
    }
}

